﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Xml;
using TomanuExtensions;
using TomanuExtensions.Utils;

namespace AmiEmuLib.AmigaConfiguration.ChipsetConfig
{
    /// <summary>
    /// Chipset configuration.
    /// </summary>
    [DebuggerDisplay("Type = {Type}")]
    public class Chipset : XmlBase
    {
        /// <summary>
        /// OCS, ECS or AGA.
        /// </summary>
        public ChipsetType Type;

        /// <summary>
        /// Source od CIA Time-Of-Day counter.
        /// </summary>
        public CIAATODSource CIAATODSource;

        /// <summary>
        /// Is teal-time clock available.
        /// </summary>
        public RealTimeClockType RealTimeClock;

        /// <summary>
        /// Can we map rom to address 0x0 at any moment, or overlay is turned on 
        /// after start and can be only disabled. Should be true for A500, A500Plus, 
        /// A1000, A3000, CDTV. In that models Gary, which is resposible for address 
        /// translation is connected to appropriate pin of CIA-A. In models past this 
        /// generations FastGary (A3000, A4000) or Gayle (A600, A12000) are not connected with CIA. 
        /// First write to any of CIA-A register turn off overlay. 
        /// </summary>
        public bool CIAOverlay;

        /// <summary>
        /// True if ROM is mirrored into this address. 
        /// </summary>
        public bool RomMirrorE0;

        /// <summary>
        /// True if ROM is mirrored into this address. 
        /// </summary>
        public bool RomMirrorA8;

        /// <summary>
        /// Should be set for A600, A1200, A4000 models which have Gayle chip.
        /// </summary>
        public IDEType IDE;

        /// <summary>
        /// Should be true for A600, A1200 models which have appropriate Gayle chip.
        /// </summary>
        public bool PCMCIA;

        /// <summary>
        /// ???
        /// </summary>
        public bool DF0IDHardware;

        /// <summary>
        /// Should be set for A3000 i A4000 models which have Ramsey chip, and 
        /// have 32-bits address space.
        /// </summary>
        public RamseyType Ramsey;

        /// <summary>
        /// Should memory at 0x00C00000 act as chip memory. Shoudl be true only for A1000.
        /// </summary>
        public bool SlowMemoryIsFast;

        /// <summary>
        /// Should be true only for one of A1000 submodel.
        /// </summary>
        public bool DeniseNoEHB;

        /// <summary>
        /// Shoudl be true only for A1000.
        /// http://en.wikipedia.org/wiki/MOS_Technology_Agnus
        /// </summary>
        public bool A1000Agnus;

        /// <summary>
        /// Allow as choose Gary (A500, A500+, CDTV, A2000) or FastGary (A3000, A4000).
        /// </summary>
        public GaryType Gary;

        /// <summary>
        /// Description: //http://cataclysm.cx/random/amiga/reference/Hardware_Manual_guide/node0178.html
        /// </summary>
        public bool KeyboardResetWarning; 

        /// <summary>
        /// Some kind of bug present in early A2000 versions and in A1000.
        /// </summary>
        public bool AgnusBlitterBusyBug;

        /// <summary>
        /// Should be true for A1000.
        /// </summary>
        public bool A1000BootRamRom;

        /// <summary>
        /// Resposible for SCSI. Should be used with CDTV, A3000, A4000.
        /// </summary>
        public DMACType DMAC;

        /// <summary>
        /// Should be true on CD32. CD logic is in AKIKO.
        /// </summary>
        public bool CD32CD;

        /// <summary>
        /// Should be true on CD32.
        /// </summary>
        public bool AkikoChunkyToPlanar;

        /// <summary>
        /// Should be true on CD32. NVRAM is wired to Akiko.
        /// </summary>
        public bool CD32NVRAM;

        /// <summary>
        /// Should ebe true for CDTV. Note this only disable CD, not SCSI controller.
        /// </summary>
        public bool CDTVCD;

        /// <summary>
        /// Should be true for CDTV. 
        /// </summary>
        public bool CDTVBatteryRAM;

        /// <summary>
        /// Should be true for CDTV. 
        /// </summary>
        public CDTVMemoryCardType CDTVMemoryCard;

        /// <summary>
        /// Decreasing compatibilty. 
        /// </summary>
        public bool BlitterImmediate;

        /// <summary>
        /// Sprite collision detection accuracy.
        /// </summary>
        public SpriteCollisionLevel SpriteCollisionLevel;

        /// <summary>
        /// PAL or NTSC.
        /// </summary>
        public TVMode TVMode;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="a_reader"></param>
        public Chipset(XmlReader a_reader)
            : base(a_reader)
        {
        }

        /// <summary>
        /// Get default amiga filter type for specified amiga model.
        /// </summary>
        /// <param name="a_model"></param>
        /// <returns></returns>
        public int GetCustomCyclePerSecond(bool a_base = false)
        {
            int result = (TVMode == TVMode.PAL) ? Consts.FREQ_PAL / 2 : Consts.FREQ_NTSC / 2;

            if (a_base)
                return result;

            if (Type == ChipsetType.AGA)
                result *= 2;

            return result;
        }

        protected override void ReadXml(XmlReader a_reader)
        {
            Type = a_reader.GetAttributeEnum<ChipsetType>("Type");

            a_reader.ReadStartElement(GetType().Name);

            CIAATODSource = a_reader.ReadElementContentAsEnum<CIAATODSource>("CIAATODSource");
            RealTimeClock = a_reader.ReadElementContentAsEnum<RealTimeClockType>("RealTimeClock");
            CIAOverlay = a_reader.ReadElementContentAsBoolean("CIAOverlay");
            RomMirrorE0 = a_reader.ReadElementContentAsBoolean("RomMirrorE0");
            RomMirrorA8 = a_reader.ReadElementContentAsBoolean("RomMirrorA8");
            IDE = a_reader.ReadElementContentAsEnum<IDEType>("IDE");
            PCMCIA = a_reader.ReadElementContentAsBoolean("PCMCIA");
            DF0IDHardware = a_reader.ReadElementContentAsBoolean("DF0IDHardware");
            Ramsey = a_reader.ReadElementContentAsEnum<RamseyType>("Ramsey");
            SlowMemoryIsFast = a_reader.ReadElementContentAsBoolean("SlowMemoryIsFast");
            DeniseNoEHB = a_reader.ReadElementContentAsBoolean("DeniseNoEHB");
            A1000Agnus = a_reader.ReadElementContentAsBoolean("A1000Agnus");
            Gary = a_reader.ReadElementContentAsEnum<GaryType>("Gary");
            KeyboardResetWarning = a_reader.ReadElementContentAsBoolean("KeyboardResetWarning");
            AgnusBlitterBusyBug = a_reader.ReadElementContentAsBoolean("AgnusBlitterBusyBug");
            A1000BootRamRom = a_reader.ReadElementContentAsBoolean("A1000BootRamRom");
            DMAC = a_reader.ReadElementContentAsEnum<DMACType>("DMAC");
            CD32CD = a_reader.ReadElementContentAsBoolean("CD32CD");
            AkikoChunkyToPlanar = a_reader.ReadElementContentAsBoolean("AkikoChunkyToPlanar");
            CD32NVRAM = a_reader.ReadElementContentAsBoolean("CD32NVRAM");
            CDTVCD = a_reader.ReadElementContentAsBoolean("CDTVCD");
            CDTVBatteryRAM = a_reader.ReadElementContentAsBoolean("CDTVBatteryRAM");
            CDTVMemoryCard = a_reader.ReadElementContentAsEnum<CDTVMemoryCardType>("CDTVMemoryCard");
            BlitterImmediate = a_reader.ReadElementContentAsBoolean("BlitterImmediate");
            SpriteCollisionLevel = a_reader.ReadElementContentAsEnum<SpriteCollisionLevel>(
                "SpriteCollisionLevel");
            TVMode = a_reader.ReadElementContentAsEnum<TVMode>("TVMode");

            a_reader.ReadEndElement();
        }

        public override void WriteXml(XmlWriter a_writer)
        {
            a_writer.WriteStartElement(GetType().Name);

            a_writer.WriteAttribute("Type", Type);
            a_writer.WriteElement("CIAATODSource", CIAATODSource);
            a_writer.WriteElement("RealTimeClock", RealTimeClock);
            a_writer.WriteElement("CIAOverlay", CIAOverlay);
            a_writer.WriteElement("RomMirrorE0", RomMirrorE0);
            a_writer.WriteElement("RomMirrorA8", RomMirrorA8);
            a_writer.WriteElement("IDE", IDE);
            a_writer.WriteElement("PCMCIA", PCMCIA);
            a_writer.WriteElement("DF0IDHardware", DF0IDHardware);
            a_writer.WriteElement("Ramsey", Ramsey);
            a_writer.WriteElement("SlowMemoryIsFast", SlowMemoryIsFast);
            a_writer.WriteElement("DeniseNoEHB", DeniseNoEHB);
            a_writer.WriteElement("A1000Agnus", A1000Agnus);
            a_writer.WriteElement("Gary", Gary);
            a_writer.WriteElement("KeyboardResetWarning", KeyboardResetWarning);
            a_writer.WriteElement("AgnusBlitterBusyBug", AgnusBlitterBusyBug);
            a_writer.WriteElement("A1000BootRamRom", A1000BootRamRom);
            a_writer.WriteElement("DMAC", DMAC);
            a_writer.WriteElement("CD32CD", CD32CD);
            a_writer.WriteElement("AkikoChunkyToPlanar", AkikoChunkyToPlanar);
            a_writer.WriteElement("CD32NVRAM", CD32NVRAM);
            a_writer.WriteElement("CDTVCD", CDTVCD);
            a_writer.WriteElement("CDTVBatteryRAM", CDTVBatteryRAM);
            a_writer.WriteElement("CDTVMemoryCard", CDTVMemoryCard);
            a_writer.WriteElement("BlitterImmediate", BlitterImmediate);
            a_writer.WriteElement("SpriteCollisionLevel", SpriteCollisionLevel);
            a_writer.WriteElement("TVMode", TVMode);

            a_writer.WriteEndElement();
        }
    }
}
